package com.boyicloud.exchangeserver.netty.listener

import com.boyicloud.exchangeserver.common.Constant
import com.boyicloud.exchangeserver.netty.handler.ExchangeHandler
import com.boyicloud.exchangeserver.netty.handler.InitializeHandler
import io.netty.bootstrap.ServerBootstrap
import io.netty.channel.ChannelInitializer
import io.netty.channel.ChannelOption

import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.SocketChannel
import io.netty.channel.socket.nio.NioServerSocketChannel
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component

@Component
class NettyServerListener {


    val log: Logger = LoggerFactory.getLogger(NettyServerListener::class.java)

    @Autowired
    lateinit var softwareInitializeHandler: InitializeHandler

    @Autowired
    lateinit var equipmentInitializeHandler: InitializeHandler

    @Autowired
    lateinit var exchangeHandler: ExchangeHandler


    fun start(port: Int, serverType: ServerType) {
        val bootstrap = ServerBootstrap()
        val bossGroup = NioEventLoopGroup(1)
        val workGroup = NioEventLoopGroup()
        bootstrap.group(bossGroup, workGroup)
            .channel(NioServerSocketChannel::class.java)
            .option(ChannelOption.SO_BACKLOG, 1024)
            .childOption(ChannelOption.SO_KEEPALIVE, true)
            .childHandler(object : ChannelInitializer<SocketChannel>() {
                override fun initChannel(channel: SocketChannel) {
                    when (serverType) {
                        ServerType.SOFTWARE -> channel.pipeline().addLast(softwareInitializeHandler)
                        ServerType.EQUIPMENT -> channel.pipeline().addLast(equipmentInitializeHandler)
                    }
                    channel.pipeline().addLast(exchangeHandler)
                }
            })

        val channelFuture = bootstrap.bind(port).sync()

        channelFuture.addListener { f ->
            run {
                if (f.isSuccess) {
                    log.info("NettySoftwareServer opened at: $port")
                }
            }

        }

        Runtime.getRuntime().addShutdownHook(
            Thread {
                bossGroup.shutdownGracefully()
                workGroup.shutdownGracefully()
            }
        )
    }

    enum class ServerType(val value: String) {
        SOFTWARE(Constant.SOFTWARE_LIST_KEY),
        EQUIPMENT(Constant.EQUIPMENT_LIST_KEY)
    }
}
